package com.motong.gongdan.service;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.motong.gongdan.constant.CommonConstant;
import com.motong.gongdan.entity.*;
import com.motong.gongdan.mapper.DeviceInfoMapper;
import com.motong.gongdan.util.LoginUtil;
import com.motong.gongdan.vo.H5Vo.lamp.query.LampDashboardQuery;
import com.motong.gongdan.vo.H5Vo.lamp.vo.LampDashboardVo;
import com.motong.gongdan.vo.system.device.query.DeviceListQuery;
import com.motong.gongdan.vo.system.device.vo.DeviceDataVo;
import com.motong.gongdan.vo.system.device.vo.DeviceListVo;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.*;

import static com.motong.gongdan.constant.CommonConstant.REDIS_KEY_PREFIX;

@Service
public class DeviceInfoService extends ServiceImpl<DeviceInfoMapper, DeviceInfo> {

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    @Resource
    private DeviceStatusService deviceStatusService;

    @Resource
    private ExceptionInfoService exceptionInfoService;

    @Resource
    private DeviceProduceLogService deviceProduceLogService;

    @Resource
    private LampTypeService lampTypeService;

    @Resource
    private LampRequestService lampRequestService;

    /**
     * @param page  分页数据
     * @param query 查询参数
     * @return 设备信息列表
     */
    public Page<DeviceListVo> getList(Page<DeviceInfo> page, DeviceListQuery query) {
        return this.baseMapper.getList(page, query);
    }

    public void changeStatus(DeviceDataVo data) {
        DeviceInfo deviceInfo = data.getDeviceInfo();
        Integer status = Integer.valueOf(data.getDeviceStatus());
        this.toChangeStatus(status, deviceInfo);
    }


    /**
     * @param realDeviceSn 设备序列号
     * @param status       状态
     */
    public void changeStatus(String realDeviceSn, Integer status) {
        LambdaQueryWrapper<DeviceInfo> deviceQW = new LambdaQueryWrapper<DeviceInfo>().eq(DeviceInfo::getRealDeviceSn, realDeviceSn);
        DeviceInfo deviceInfo = this.getOne(deviceQW);
        LoginUtil.setIgnoreFactory(false);
        if (Objects.nonNull(deviceInfo) && !deviceInfo.getStatus().equals(status)) {
            LoginUtil.setLoginUserFactory(deviceInfo.getFactoryId());
            this.toChangeStatus(status, deviceInfo);
        }
        LoginUtil.setIgnoreFactory(true);
    }

    public void toChangeStatus(Integer status, DeviceInfo deviceInfo) {
        LambdaQueryWrapper<DeviceStatus> deviceStatusQW = new LambdaQueryWrapper<DeviceStatus>().eq(DeviceStatus::getStatus, deviceInfo.getStatus())
                .eq(DeviceStatus::getDeviceId, deviceInfo.getId()).isNull(DeviceStatus::getDuration).orderByDesc(DeviceStatus::getCreateTime)
                .last("LIMIT 1");
        DeviceStatus deviceStatus = deviceStatusService.getOne(deviceStatusQW);
        List<DeviceStatus> deviceStatusList = new ArrayList<>(2);
        deviceInfo.setStatus(status).setUpdateTime(new Date());
        if (Objects.nonNull(deviceStatus)) {
            deviceStatus.setDuration(DateUtil.between(deviceStatus.getCreateTime(), new Date(), DateUnit.SECOND));
            deviceStatusList.add(deviceStatus);
        }
        DeviceStatus newDeviceStatus = new DeviceStatus().setDeviceId(deviceInfo.getId()).setCreateTime(new Date()).setStatus(status);
        newDeviceStatus.setFactoryId(deviceInfo.getFactoryId());
        deviceStatusList.add(newDeviceStatus);
        if (!CollectionUtils.isEmpty(deviceStatusList)) {
            deviceStatusService.saveOrUpdateBatch(deviceStatusList);
        }

        //修改异常时间
        ExceptionInfo existExceptionInfo = exceptionInfoService.getOne(new LambdaQueryWrapper<ExceptionInfo>()
                .eq(ExceptionInfo::getDeviceId, deviceInfo.getId()).eq(ExceptionInfo::getFactoryId, deviceInfo.getFactoryId())
                .isNull(ExceptionInfo::getEndTime));
        if (Objects.nonNull(existExceptionInfo)) {
            existExceptionInfo.setEndTime(new Date());
            exceptionInfoService.updateById(existExceptionInfo);
        }
        this.saveOrUpdate(deviceInfo);
    }


    public DeviceInfo getBySn(String sn) {
        return this.getOne(new LambdaQueryWrapper<DeviceInfo>().eq(DeviceInfo::getRealDeviceSn, sn));
    }


    /**
     * @param page  分页信息
     * @param query 查询信息
     */
    public Page<LampDashboardVo> getLampDashboardList(Page<LampDashboardVo> page, LampDashboardQuery query) {
        return this.baseMapper.getLampDashboardList(page, query);
    }

    /**
     * @param deviceSn 设备序列号
     * @param jsonData json数据
     * @return 变化的可操作数据
     */
    public DeviceDataVo getAvailableData(String deviceSn, JSONObject jsonData) {
        if (CollectionUtils.isEmpty(jsonData)) {
            log.warn(String.format("设备序列号%s接收到空数据", deviceSn));
            return null;
        }
        DeviceInfo deviceInfo = this.getBySn(deviceSn);
        if (Objects.isNull(deviceInfo)) {
            log.warn(String.format("设备序列号%s不存在或序列号已变更", deviceSn));
            return null;
        }
        DeviceDataVo oriData = this.getOriDataFromJson(jsonData, deviceInfo);
        oriData.setDeviceInfo(deviceInfo).setDeviceSn(deviceSn);
        return this.checkChange(deviceInfo, oriData);
    }

    /**
     * @param deviceInfo 设备信息
     * @param oriData    原始解析数据
     * @return 变化数据
     */
    private DeviceDataVo checkChange(DeviceInfo deviceInfo, DeviceDataVo oriData) {
        if (oriData.isCloseStatus()) {
            oriData.setDeviceStatus("0");
        }
        if (Objects.nonNull(oriData.getDeviceStatus())) {
            String oldData = Optional.ofNullable(deviceInfo.getStatus()).orElse(-1).toString();
            if (oriData.getDeviceStatus().equals(oldData)) {
                oriData.setDeviceStatus(null);
            }
        }
        if (Objects.nonNull(oriData.getCSQ())) {
            String oldData = Optional.ofNullable(deviceInfo.getCSQ()).orElse("");
            if (oriData.getCSQ().equals(oldData)) {
                oriData.setCSQ(null);
            } else {
                deviceInfo.setCSQ(oriData.getCSQ());
            }
        }
        if (Objects.nonNull(oriData.getDeviceCount())) {
            String oldData;
            Object oldDataObj = redisTemplate.opsForHash().get(REDIS_KEY_PREFIX.concat("device:count"), deviceInfo.getRealDeviceSn());
            oldData = Optional.ofNullable(oldDataObj).orElse(deviceProduceLogService.getLastByDeviceId(deviceInfo.getId()).getCount()).toString();
            if (oriData.getDeviceCount().equals(oldData)) {
                oriData.setDeviceCount(null);
            }
        }
        if (Objects.nonNull(oriData.getLampBStatus())) {
            String oldData;
            Object oldDataObj = redisTemplate.opsForHash().get(REDIS_KEY_PREFIX.concat("device:lampBStatus"), deviceInfo.getRealDeviceSn());
            oldData = Optional.ofNullable(oldDataObj).orElse(-1).toString();
            if (oriData.getLampBStatus().equals(oldData)) {
                oriData.setLampBStatus(null);
            }
        }
        return oriData;
    }

    /**
     * @param jsonData json数据
     * @return 从json中获取原始数据
     */
    private DeviceDataVo getOriDataFromJson(JSONObject jsonData, DeviceInfo deviceInfo) {
        DeviceDataVo deviceDataVo = new DeviceDataVo();
        String redStatus = null;
        String greenStatus = null;
        String yellowStatus = null;
        String blueStatus = null;
        for (Map.Entry<String, Object> object : jsonData) {
            String k = object.getKey();
            String v = object.getValue().toString();
            if (k.endsWith("G")) {
                greenStatus = v;
            }
            if (k.endsWith("Y")) {
                yellowStatus = v;
            }
            if (k.endsWith("R")) {
                redStatus = v;
            }
            if (k.endsWith("B")) {
                blueStatus = v;
                deviceDataVo.setLampBStatus(v);
                if ("2".equals(v)) {
                    deviceDataVo.setCloseStatus(false);
                }
            }
            if (k.contains("cause")) {
                deviceDataVo.setCause(v);
            }
            if (k.contains("JS")) {
                deviceDataVo.setDeviceCount(v);
            }
            if (k.contains("_CSQ")) {
                deviceDataVo.setCSQ(v);
            }
            //总时间
            if (k.contains("ZSJ")) {
            }
            //合时间
            if (k.contains("HSJ")) {
            }
            //分时间
            if (k.contains("FSJ")) {
            }
            //蜂鸣器
            if (k.contains("BU")) {
                deviceDataVo.setBU(v);
            }
        }
        //状态判断
        if (Objects.isNull(redStatus) && Objects.isNull(yellowStatus) && Objects.isNull(greenStatus)) {
            deviceDataVo.setCloseStatus(false);
        } else {
            if (Objects.nonNull(redStatus) && "1".equals(redStatus)) {
                deviceDataVo.setCloseStatus(false);
                deviceDataVo.setDeviceStatus("3");
                deviceDataVo.setExceptionLampColor("1");
            } else if (Objects.nonNull(greenStatus) && "1".equals(greenStatus)) {
                deviceDataVo.setCloseStatus(false);
                deviceDataVo.setDeviceStatus("1");
            } else if (Objects.nonNull(yellowStatus) && "1".equals(yellowStatus)) {
                deviceDataVo.setCloseStatus(false);
                deviceDataVo.setDeviceStatus("2");
                deviceDataVo.setExceptionLampColor("0");
            }
            if (deviceInfo.getStatus().equals(1) && (Objects.isNull(greenStatus) || !"0".equals(greenStatus))) {
                deviceDataVo.setCloseStatus(false);
            }
            if (deviceInfo.getStatus().equals(2) && (Objects.isNull(yellowStatus) || !"0".equals(yellowStatus))) {
                deviceDataVo.setCloseStatus(false);
            }
            if (deviceInfo.getStatus().equals(3) && (Objects.isNull(redStatus) || !"0".equals(redStatus))) {
                deviceDataVo.setCloseStatus(false);
            }
        }
        if (Objects.nonNull(blueStatus) && "2".equals(blueStatus)) {
            deviceDataVo.setLampBStatus(blueStatus);
            deviceDataVo.setCloseStatus(false);
        }
        return deviceDataVo;
    }

    public void changeCount(DeviceDataVo data) {
        Long nowCount = Long.parseLong(data.getDeviceCount());
        DeviceInfo deviceInfo = data.getDeviceInfo();
        Date date = new Date();
//        Long dateTime = date.getTime();
        DeviceProduceLog deviceProduceLog = new DeviceProduceLog().setDeviceId(deviceInfo.getId()).setCount(nowCount)
                .setMissionId(deviceInfo.getMissionId()).setCreateTime(date);
        //获取上一条记录的记录时间
//        Object deviceLastTime = redisTemplate.opsForHash().get(CommonConstant.DEVICE_LAST_PRODUCE_TIME_HASH_LEY, deviceInfo.getId());
        Date lastDate = date;
        Long lastCount = 0L;
//        if (Objects.nonNull(deviceLastTime)) {
//            try {
//                lastDate = new Date(Long.parseLong(deviceLastTime.toString()));
//            } catch (Exception e) {
//                lastDate = null;
//            }
//        }
//        if (Objects.isNull(lastDate)) {
        //获取最后一条生产记录
        Object lastProduceLogO = redisTemplate.opsForHash().get(CommonConstant.DEVICE_LAST_PRODUCE_LOG, deviceInfo.getId().toString());
        DeviceProduceLog lastLog;
        if (Objects.nonNull(lastProduceLogO)) {
            lastLog = JSONUtil.toBean(lastProduceLogO.toString(), DeviceProduceLog.class);
        } else {
            LambdaQueryWrapper<DeviceProduceLog> deviceProduceLogQW = new LambdaQueryWrapper<DeviceProduceLog>()
                    .eq(DeviceProduceLog::getDeviceId, deviceInfo.getId()).orderByDesc(DeviceProduceLog::getId).last("LIMIT 1");
            lastLog = deviceProduceLogService.getOne(deviceProduceLogQW);
        }
        if (Objects.nonNull(lastLog)) {
            if (Objects.nonNull(lastLog.getCreateTime())) {
                lastDate = lastLog.getCreateTime();
            }
            if (Objects.nonNull(lastLog.getCount())) {
                lastCount = lastLog.getCount();
            }
        }
//        }
        long timeInterval = DateUtil.between(lastDate, date, DateUnit.SECOND);
        deviceProduceLog.setTimeInterval(timeInterval);
        long realCount = nowCount - lastCount;
        deviceProduceLog.setRealCount(Math.max(realCount, 0L));
        deviceProduceLogService.save(deviceProduceLog);
        redisTemplate.opsForHash().put(CommonConstant.DEVICE_LAST_PRODUCE_LOG, deviceInfo.getId().toString(), JSONUtil.toJsonStr(deviceProduceLog));
    }

    public void senDefaultLampRequest(DeviceDataVo data) {
        DeviceInfo deviceInfo = data.getDeviceInfo();
        LambdaQueryWrapper<LampType> lastQW = new LambdaQueryWrapper<LampType>().eq(LampType::getGroupId, deviceInfo.getGroupId()).eq(LampType::getFactoryId, deviceInfo.getFactoryId())
                .orderByDesc(LampType::getCreateTime).last("LIMIT 1");
        LampType lampType = lampTypeService.getOne(lastQW);
        if (Objects.nonNull(lampType)) {
            lampRequestService.sendDefaultLampRequestByLampType(deviceInfo, lampType);
        }
    }
}
